<?php

namespace app\controller;

use app\BaseController;
use openapi\ApiDoc;
use openapi\oas\Service as OASService;

/**
 * API文档控制器
 */
class Doc extends BaseController
{
	/**
	 * 文档跳转
	 */
	public function index()
	{
		$jsonUrl = url('/Doc/getApiGroupJson', [], false, true)->build();
		$htmlUrl = url('/apidoc/index.html', [], false, true)->build();

		$url = $htmlUrl . '?group=' . $jsonUrl;

		if (request()->isAjax()) {
			return success($url);
		}
		return redirect($url);
	}

	/**
	 * 文档说明
	 */
	public function readme()
	{
		$br = '<br/>';
		$str = '应用模式: ' . env('app.mode') . $br;
		$str .= 'api文档请访问: ' . url('/doc', [], false, true) . $br;
		return $str;
	}

	/**
	 * 获取文档整体json
	 */
	public function getApiGroupJson()
	{
		$url = url('/Doc/getApiDocJson', [], false, true);
		return json([
			[
				'name' => '小程序端',
				'link' =>  $url->vars(['group' => 'weappapi'])->build()
			],
			[
				'name' => '后台管理端',
				'link' => $url->vars(['group' => 'adminapi'])->build()
			],
			[
				'name' => 'SDK接口',
				'link' => $url->vars(['group' => 'sdkapi'])->build()
			],
		]);
	}

	/**
	 * 获取接口文档数据
	 * @param string $group 分组名称
	 */
	public function getApiDocJson($group = '')
	{
		// 扫描API
		$oas = (new ApiDoc(__DIR__ . '/' . $group))->parseClassToApi();

		// 整个api的说明
		$oas->info->title = '项目名';
		$oas->info->description = '项目说明';
		$oas->info->version = 'v1.0.0';

		// 环境
		$service = new OASService();
		$service->url = url('/', [], false, true)->build();
		$service->description = '测试环境';
		$oas->servers[] = $service;

		return json($oas);
	}

	/**
	 * 获取常用模型枚举
	 * 要求: 模型上定义 const 字段，注解第一行必须写 @var array XXX，值为数组
	 */
	public function getEnums()
	{
		// 获取所有模型php文件
		$modelDir = app_path('model');
		$modelFiles = glob($modelDir . '/*.php');

		// 反射所有模型类
		$result = [];
		foreach ($modelFiles as $file) {
			$model = new \ReflectionClass('app\model\\' . basename($file, '.php'));
			$modelConstants = $model->getReflectionConstants();
			$modelSortName = $model->getShortName();

			$constants = [];
			// 还需要获取常量上面的注解
			foreach ($modelConstants as $constant) {
				$constantValue = $constant->getValue();
				if (!is_array($constantValue)) continue;

				$constantName = $constant->getName();

				$constantCnName = '';
				foreach (parseReflectionComment($constant->getDocComment()) as $docLine) {
					if (($docLine[0] ?? '') === 'var') {
						$constantCnName = $docLine[2];
						break;
					}
				}

				$constants[$constantName] = [
					'key' => $constantName,
					'name' => $constantCnName,
					'value' => $constantValue,
					'api' => "Other_getModelMap({ model:'" . $modelSortName . "', field:'" . $constantName . "' })",
					'url' => url('/sdkapi/Other/getModelMap', ['model' => $modelSortName, 'field' => $constantName], false, true)->build(),
				];
			}

			if (count($constants)) $result[] = [
				'model' => $modelSortName,
				'name' => property_exists($model->getName(), 'modelAlias')
					? $model->getStaticPropertyValue('modelAlias')
					: $modelSortName,
				'constants' => $constants,
			];
		}

		if (request()->isAjax()) return success($result);

		$html = '<style>td{padding:2px 4px}</style>';

		// 返回一个html的<table>来渲染这些数据，表头如下
		// 模型英文名 | 模型中文名 | 常量名  | 常量中文名 | 常量值 | 接口api文本 | 打开接口（跳转）
		// 模型英文名和模型中文名这两列，要分组合并
		$html .= '<table border="1" cellspacing="0" cellpadding="0">';
		$html .= '<tr><th>模型英文名</th><th>模型中文名</th><th>常量名</th><th>常量中文名</th><th>常量值</th><th>接口api文本</th><th>打开接口（跳转）</th></tr>';
		foreach ($result as $model) {
			$modelName = $model['model'];
			$modelCnName = $model['name'];
			foreach ($model['constants'] as $constant) {
				$constantName = $constant['key'];
				$constantCnName = $constant['name'];
				$constantValue = json_encode($constant['value'], JSON_UNESCAPED_UNICODE);
				$constantApi = $constant['api'];
				$constantUrl = $constant['url'];

				$html .= "<tr><td>{$modelName}</td><td>{$modelCnName}</td><td>{$constantName}</td><td>{$constantCnName}</td><td>{$constantValue}</td><td>{$constantApi}</td><td><a href='{$constantUrl}' target='_blank'>打开接口</a></td></tr>";
			}
		}
		$html .= '</table>';

		return $html;
	}
}
